#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
应用程序框架分析器 - 主窗口
实现分析器的图形界面
"""

import os
import sys
import threading
import tkinter as tk
from tkinter import ttk, filedialog, scrolledtext, messagebox
from pathlib import Path
from datetime import datetime
import logging

# 导入工具函数
from src.gui.utils import init_drag_and_drop, load_config
from src.core.analyzer import AppAnalyzer as Analyzer

# 设置日志
logger = logging.getLogger("FrameworkAnalyzerGUI")

class FrameworkAnalyzerGUI:
    """应用程序框架分析器图形界面"""
    
    def __init__(self, root):
        """初始化图形界面"""
        self.root = root
        self.config_data = load_config()
        self.setup_ui()
        
        # 设置拖放功能
        self.setup_drag_drop()
        
        # 分析状态
        self.is_analyzing = False
    
    def setup_ui(self):
        """设置用户界面"""
        # 配置主窗口
        self.root.title("应用程序框架分析器")
        self.root.geometry("900x700")
        self.root.minsize(800, 600)
        
        # 创建样式
        style = ttk.Style()
        style.configure("TFrame", background="#f5f5f5")
        style.configure("TButton", font=("Microsoft YaHei UI", 10))
        style.configure("TLabel", font=("Microsoft YaHei UI", 10), background="#f5f5f5")
        style.configure("Header.TLabel", font=("Microsoft YaHei UI", 16, "bold"), background="#f5f5f5")
        style.configure("Result.TLabel", font=("Microsoft YaHei UI", 12, "bold"), background="#f5f5f5")
        
        # 主框架
        main_frame = ttk.Frame(self.root, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 标题
        header = ttk.Label(main_frame, text="应用程序框架分析器", style="Header.TLabel")
        header.pack(pady=(0, 20))
        
        # 文件选择区域
        file_frame = ttk.Frame(main_frame)
        file_frame.pack(fill=tk.X, pady=10)
        
        ttk.Label(file_frame, text="应用程序路径:").pack(side=tk.LEFT, padx=(0, 10))
        
        self.path_var = tk.StringVar()
        path_entry = ttk.Entry(file_frame, textvariable=self.path_var, width=50)
        path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
        
        browse_btn = ttk.Button(file_frame, text="选择文件", command=self.browse_file)
        browse_btn.pack(side=tk.LEFT, padx=(0, 5))
        
        browse_dir_btn = ttk.Button(file_frame, text="选择文件夹", command=self.browse_directory)
        browse_dir_btn.pack(side=tk.LEFT)
        
        # 平台选择区域
        platform_frame = ttk.Frame(main_frame)
        platform_frame.pack(fill=tk.X, pady=10)
        
        ttk.Label(platform_frame, text="平台:").pack(side=tk.LEFT, padx=(0, 10))
        
        platforms = ["auto", "windows", "macos", "linux", "android", "ios", "harmony"]
        self.platform_var = tk.StringVar(value="auto")
        platform_combo = ttk.Combobox(platform_frame, textvariable=self.platform_var, values=platforms, state="readonly", width=15)
        platform_combo.pack(side=tk.LEFT)
        
        # 拖放提示区域
        drop_frame = ttk.Frame(main_frame, padding=10)
        drop_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        
        self.drop_label = ttk.Label(drop_frame, text="将应用程序包或文件夹拖放到此处进行分析", 
                                   background="#e9ecef", foreground="#495057", 
                                   borderwidth=2, relief="solid", anchor="center")
        self.drop_label.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 分析按钮
        self.analyze_btn = ttk.Button(main_frame, text="开始分析", command=self.start_analysis)
        self.analyze_btn.pack(pady=15)
        
        # 进度条
        self.progress = ttk.Progressbar(main_frame, mode='indeterminate')
        self.progress.pack(fill=tk.X, pady=5)
        self.progress.pack_forget()  # 初始隐藏进度条
        
        # 结果区域
        result_frame = ttk.LabelFrame(main_frame, text="分析结果", padding=10)
        result_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        
        self.result_text = scrolledtext.ScrolledText(result_frame, wrap=tk.WORD, height=12, font=("Microsoft YaHei UI", 10))
        self.result_text.pack(fill=tk.BOTH, expand=True)
        self.result_text.config(state=tk.DISABLED)
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(self.root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)
    
    def setup_drag_drop(self):
        """设置拖放功能"""
        try:
            self.drop_label.drop_target_register(DND_FILES)
            self.drop_label.dnd_bind('<<Drop>>', self.handle_drop)
        except NameError:
            logger.warning("DND_FILES未定义，拖放功能不可用")
        except Exception as e:
            logger.error(f"设置拖放功能失败: {e}")
    
    def handle_drop(self, event):
        """处理文件拖放"""
        # 从拖放信息中获取文件路径
        file_path = event.data
        
        # 处理不同操作系统格式的路径
        if file_path.startswith('{') and file_path.endswith('}'):
            file_path = file_path[1:-1]
        
        # 处理Windows路径格式
        if sys.platform == 'win32':
            file_path = file_path.replace('\\', '/')
            if file_path.startswith('"') and file_path.endswith('"'):
                file_path = file_path[1:-1]
        
        # 处理选择的路径
        self._process_selected_path(file_path)
        
        # 自动开始分析
        self.start_analysis()
    
    def browse_file(self):
        """浏览并选择文件或目录"""
        # 使用askdirectory同时支持选择文件和文件夹
        from tkinter import filedialog as fd
        
        file_path = fd.askopenfilename(
            title="选择应用程序文件",
            filetypes=[
                ("所有应用程序包", "*.exe;*.msi;*.msix;*.appx;*.apk;*.ipa;*.app;*.deb;*.rpm;*.hap"),
                ("Windows应用", "*.exe;*.msi;*.msix;*.appx"),
                ("Android应用", "*.apk;*.aab"),
                ("iOS应用", "*.ipa"),
                ("所有文件", "*.*")
            ]
        )
        
        if file_path:
            self._process_selected_path(file_path)
    
    def browse_directory(self):
        """浏览并选择目录"""
        dir_path = filedialog.askdirectory(
            title="选择应用程序目录"
        )
        
        if dir_path:
            self._process_selected_path(dir_path)
    
    def _process_selected_path(self, path):
        """处理选择的路径"""
        self.path_var.set(path)
        
        # 检查是否为目录
        path_obj = Path(path)
        if path_obj.is_dir():
            # 如果是目录，设置为自动检测平台
            self.platform_var.set('auto')
        else:
            # 根据文件类型选择平台
            file_ext = path_obj.suffix.lower()
            if file_ext in ['.exe', '.msi', '.msix', '.appx']:
                self.platform_var.set('windows')
            elif file_ext in ['.apk', '.aab']:
                self.platform_var.set('android')
            elif file_ext in ['.ipa']:
                self.platform_var.set('ios')
            elif file_ext in ['.app', '.dmg']:
                self.platform_var.set('macos')
            elif file_ext in ['.hap']:
                self.platform_var.set('harmony')
            elif file_ext in ['.deb', '.rpm', '.appimage']:
                self.platform_var.set('linux')
            else:
                self.platform_var.set('auto')
    
    def start_analysis(self):
        """开始分析应用程序"""
        if self.is_analyzing:
            messagebox.showinfo("提示", "正在分析中，请稍候...")
            return
        
        app_path = self.path_var.get().strip()
        if not app_path:
            messagebox.showwarning("警告", "请选择或拖入应用程序包！")
            return
        
        if not Path(app_path).exists():
            messagebox.showerror("错误", f"路径不存在: {app_path}")
            return
        
        # 更新UI状态
        self.is_analyzing = True
        self.status_var.set("正在分析中...")
        self.analyze_btn.config(state=tk.DISABLED)
        self.progress.pack(fill=tk.X, pady=5)
        self.progress.start(10)
        
        # 清空结果区域
        self.result_text.config(state=tk.NORMAL)
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, f"开始分析: {app_path}\n")
        self.result_text.insert(tk.END, f"平台: {self.platform_var.get()}\n")
        self.result_text.insert(tk.END, "分析中，请稍候...\n\n")
        self.result_text.config(state=tk.DISABLED)
        
        # 在后台线程中执行分析
        threading.Thread(target=self.run_analysis, daemon=True).start()
    
    def run_analysis(self):
        """在后台线程中运行分析过程"""
        try:
            app_path = self.path_var.get().strip()
            platform = self.platform_var.get()
            
            # 创建输出目录
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            output_path = Path("./reports") / f"report_{timestamp}"
            
            # 创建分析器实例
            analyzer = Analyzer(
                app_path=Path(app_path),
                platform=platform,
                output_path=output_path,
                config=self.config_data,
                verbose=True
            )
            
            # 执行分析
            result = analyzer.analyze()
            
            # 更新结果显示
            self.root.after(0, lambda: self.update_result(result, output_path))
            
        except Exception as e:
            error_msg = f"分析过程中发生错误: {str(e)}"
            logger.error(error_msg)
            import traceback
            logger.error(traceback.format_exc())
            self.root.after(0, lambda: self.show_error(error_msg))
        finally:
            # 恢复UI状态
            self.root.after(0, self.reset_ui)
    
    def update_result(self, result, output_path):
        """更新分析结果显示"""
        # 获取结果摘要
        summary = result.summary()
        
        # 更新结果文本区域
        self.result_text.config(state=tk.NORMAL)
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, summary)
        self.result_text.insert(tk.END, f"\n\n分析报告已保存至: {output_path}\n")
        
        # 如果有识别到框架，添加详细信息
        if result.frameworks:
            self.result_text.insert(tk.END, "\n框架详细信息:\n")
            for fw in result.frameworks:
                self.result_text.insert(tk.END, f"\n- {fw.name} {fw.version or ''}\n")
                self.result_text.insert(tk.END, f"  置信度: {fw.confidence:.2f}\n")
                
                if fw.features:
                    self.result_text.insert(tk.END, "  特征:\n")
                    for feature in fw.features:
                        self.result_text.insert(tk.END, f"   * {feature}\n")
        
        # 添加查看报告的提示
        self.result_text.insert(tk.END, "\n可以打开生成的HTML报告查看更多详细信息。\n")
        self.result_text.config(state=tk.DISABLED)
        
        # 更新状态栏
        self.status_var.set(f"分析完成 - 已识别 {len(result.frameworks)} 个框架")
        
        # 询问是否打开报告
        if messagebox.askyesno("分析完成", "是否打开详细报告?"):
            try:
                import webbrowser
                # 查找HTML报告文件
                html_report = list(output_path.glob("report*.html"))
                if html_report:
                    # 找到HTML报告，直接打开
                    webbrowser.open(str(html_report[0].absolute()))
                elif (output_path / "index.html").exists():
                    # 查找index.html
                    webbrowser.open(str((output_path / "index.html").absolute()))
                else:
                    # 如果没找到HTML，尝试查找可能的其他格式
                    all_reports = list(output_path.glob("*.*"))
                    if all_reports:
                        webbrowser.open(str(all_reports[0].absolute()))
                    else:
                        # 如果没有任何文件，显示错误
                        raise FileNotFoundError("报告目录中未找到任何文件")
            except Exception as e:
                logger.error(f"打开报告失败: {e}")
                messagebox.showerror("错误", f"无法打开报告: {str(e)}")
    
    def show_error(self, error_msg):
        """显示错误信息"""
        self.result_text.config(state=tk.NORMAL)
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, f"错误: {error_msg}\n")
        self.result_text.config(state=tk.DISABLED)
        
        messagebox.showerror("分析错误", error_msg)
        self.status_var.set("分析失败")
    
    def reset_ui(self):
        """重置UI状态"""
        self.progress.stop()
        self.progress.pack_forget()
        self.analyze_btn.config(state=tk.NORMAL)
        self.is_analyzing = False 
